# -*- coding;utf-8 -*-
"""
File name : serializers.PY
Program IDE : PyCharm
Create file time: 2022/4/3 17:06
File Create By Author : 朱清闯
"""
from .models import KnowledgePoint, ImageOfQuestion, Questions, QUESTION_TYPE_CHOICES, KnowledgePoint2Question
from .models import APPLICATION_STATUS_CHOICE, ExaminationPaper, User, Section, Chapter, Course, Subject, GeneralPaperApplication
from .models import JointPaperApplication, GuidePaperApplication, QuestionOnlineApplication, GuidePaper, QuestionFeedback
from .models import Feedback, GuidePaperFeedback, DownloadGuidePaperLog, DownloadQuestionLog, ChallengePaperOfUser
from .models import WrongQuestion, SwiperImage, Bulletin, Category, Book, PermitExplainPaperOfUser, UserDoQuestionLog
from .models import Video, PermitVideoOfQuestion, UserPlayVideoLog, DownloadExaminationPaperLog, Question, Tag, Node
from .models import Node2Question, NodeCooperation, QuestionPrivateOnlineApplication, Tag2Question, TagQuestion
from .models import Seatwork, QuestionOfWork, SetWork, WorkRecord, WorkRecordItem
from account.models import TRANSACTION_STATUS_CHOICE
from rest_framework import serializers
from rest_framework.serializers import ListSerializer
from account.serializers import UserSimpleModelSerializer
from rest_framework_bulk.serializers import BulkListSerializer, BulkSerializerMixin
from django.conf import settings
import re
from PIL import Image
from urllib.parse import unquote
from account.serializers import ClassGradeModelSerializer
import os
from dotenv import load_dotenv

# 加载项目根目录下的 .env 文件
load_dotenv()
date_format = "%Y-%m-%d"
four_space = "&nbsp;&nbsp;&nbsp;&nbsp;"


def convert_dic_list(dict_list, key='id'):
    # 使用列表推导式提取每个字典中'id'的值
    return [d[key] for d in dict_list]


class StringListField(serializers.ListField):
    child = serializers.CharField()

    def to_representation(self, data):
        return ' '.join(data.values_list('name', flat=True))


class KnowledgePointSerializer(serializers.ModelSerializer):
    question = serializers.SerializerMethodField(read_only=True)

    def get_question(self, obj):
        question = obj.question.all()
        serializer = QuestionSerializer(question, many=True)
        return serializer.data

    class Meta:
        model = KnowledgePoint
        fields = "__all__"


# 公有题库使用的标签
class TagPublicSerializer(serializers.ModelSerializer):
    question = serializers.SerializerMethodField(read_only=True)

    def get_question(self, obj):
        question = obj.questions_set.all()
        serializer = QuestionSerializer(question, many=True)
        return serializer.data

    class Meta:
        model = Tag
        fields = "__all__"


# 私有题库使用的标签
class TagSerializer(serializers.ModelSerializer):
    question = serializers.SerializerMethodField(read_only=True)

    def get_question(self, obj):
        question = obj.question_set.all()
        serializer = QuestionPrivateSerializer(question, many=True)
        return serializer.data

    class Meta:
        model = Tag
        fields = "__all__"


def get_children_question_count(node: Node):
    s = 0
    children = Node.objects.filter(parent__id=node.id)
    if not children:
        if node.question:
            return node.question.count()
        else:
            return 0
    else:
        # print('children:', children)
        for child in children:
            s += get_children_question_count(child)
        return s


# 章节节点
class NodeSerializer(serializers.ModelSerializer):
    question_count = serializers.SerializerMethodField(read_only=True)
    add_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    owner_name = serializers.CharField(source='owner.username', read_only=True)
    cover_front = serializers.SerializerMethodField(read_only=True)
    teamworker_name = serializers.SerializerMethodField(read_only=True)

    @staticmethod
    def get_question_count(obj):
        print('parent node:', obj)
        question_count = get_children_question_count(obj)
        return question_count

    @staticmethod
    def get_cover_front(obj):
        cover = obj.cover
        return settings.SERVER_IP + cover

    @staticmethod
    def get_teamworker_name(obj):
        teamworker = NodeCooperation.objects.filter(node__id=obj.id).values('user_id')
        user = User.objects.filter(id__in=teamworker)
        user_list = []
        if user:
            user_name = user.values('username')
            user_list = convert_dic_list(dict_list=user_name, key='username')
        return user_list

    class Meta:
        model = Node
        fields = "__all__"


# 只包含id和name属性，用于小程序端
class KnowledgePointSimpleSerializer(serializers.ModelSerializer):

    class Meta:
        model = KnowledgePoint
        fields = ['id', 'name']


class ImageOfQuestionModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = ImageOfQuestion
        fields = '__all__'


class ManyQuestionSerializer(BulkSerializerMixin, serializers.ModelSerializer):
    class Meta:
        model = Questions
        fields = '__all__'
        depth = 2
        list_serializer_class = BulkListSerializer


class QuestionMultiSerializer(BulkSerializerMixin, serializers.ModelSerializer):
    owner_name = serializers.CharField(source='owner.username', read_only=True)

    class Meta(object):
        model = Questions
        fields = '__all__'
        depth = 1
        list_serializer_class = BulkListSerializer

    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        question_obj = Questions.objects.create(**validated_data)
        return question_obj


# 反序列化，即前端发送json格式给服务器。前端不需要传递owner，重写create()方法，从request.user赋值给owner
class QuestionDeserializer(serializers.ModelSerializer):
    owner_name = serializers.CharField(source='owner.username', read_only=True)
    knowledgepoint_value = serializers.CharField(source='knowledgepoint.name', read_only=True)

    class Meta:
        model = Questions
        fields = ["id", 'content', 'answer', 'explain', 'reference', 'type', 'difficulty_level', 'publish_time',
                  'owner_name', 'open_level', 'top', 'knowledgepoint', 'order', 'pictures', 'pictures_explain',
                  'knowledgepoint_value']

    # 添加拥有者, 并将列表串联成字符串，存储在pictures字段中
    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        image_list = self.context['request'].data.pop('pictures')
        if image_list:
            images_str = "".join(image_list)
            validated_data['pictures'] = images_str
        question_obj = Questions.objects.create(**validated_data)
        return question_obj

    # 反序列化，即前端发送json格式给服务器。前端不需要传递owner，重写create()方法，从request.user赋值给owner


class CreateQuestionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Questions
        fields = ['content', 'answer', 'explain', 'reference', 'type', 'difficulty_level',
                  'open_level', 'knowledgepoint', 'pictures', 'pictures_explain']

    # 添加拥有者
    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        question_obj = Questions.objects.create(**validated_data)
        return question_obj


class QuestionNoFavoritesSerializer(serializers.ModelSerializer):
    owner_name = serializers.CharField(source='owner.username', read_only=True)
    knowledgepoint_cn = serializers.CharField(source='knowledgepoint.name', read_only=True)
    publish_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    type_cn = serializers.SerializerMethodField(read_only=True)

    def get_type_cn(self, obj):
        question_type = obj.type
        return QUESTION_TYPE_CHOICES[question_type][1]

    class Meta:
        model = Questions
        fields = ["id", 'content', 'answer', 'explain', 'reference', 'type', 'difficulty_level', 'publish_time',
                  'open_level', 'top', 'order', 'pictures', 'pictures_explain', 'owner_name',
                  'type_cn']


class KnowledgePoint2QuestionSerializer(serializers.ModelSerializer):
    # knowledgepoint = KnowledgePointSerializer()
    # question = QuestionDeserializer()

    class Meta:
        model = KnowledgePoint2Question
        fields = "__all__"


class NodeCooperationSerializer(serializers.ModelSerializer):
    user_name = serializers.CharField(source='user.username', read_only=True)
    node_cn = serializers.CharField(source='node.name', read_only=True)

    class Meta:
        model = NodeCooperation
        fields = "__all__"


class Node2QuestionSerializer(serializers.ModelSerializer):

    class Meta:
        model = Node2Question
        fields = "__all__"


class QuestionListSerializer(ListSerializer):
    def update(self, instance, validated_data):
        for index, obj in enumerate(instance):
            self.child.update(obj, validated_data[index])
        return instance


regular_rule_content = r'(.*)A\s*[\.\．]'
regular_rule_A = r'A\s*[\.\．](.*)B[\.\．]'
regular_rule_B = r'B\s*[\.\．](.*)C[\.\．]'
regular_rule_C = r'C\s*[\.\．](.*?)D[\.\．]'
regular_rule_D = r'D\s*[\.\．](.*)'


def get_option(content):
    temp_content = content
    content = re.sub(r'<p>|</p>', '', content)
    flag = False
    option_list = []
    content_front_no_option = ''
    if re.search(regular_rule_A, content, re.S):
        option_temp = re.search(regular_rule_A, content, re.S).group(1)
        option_list.append('A.' + option_temp.strip())
    if re.search(regular_rule_B, content, re.S):
        option_temp = re.search(regular_rule_B, content, re.S).group(1)
        option_list.append('B.' + option_temp.strip())
    if re.search(regular_rule_C, content, re.S):
        option_temp = re.search(regular_rule_C, content, re.S).group(1)
        option_list.append('C.' + option_temp.strip())
    if re.search(regular_rule_D, content, re.S):
        option_temp = re.search(regular_rule_D, content, re.S).group(1)
        option_list.append('D.' + option_temp.strip())
    if re.search(regular_rule_content, content, re.S):
        content_front_no_option = re.search(regular_rule_content, temp_content, re.S).group(1)
        # 去掉尾部多余的<p>标签
        if content_front_no_option[-3:] == '<p>':
            content_front_no_option = content_front_no_option[:-3]
        elif content_front_no_option[-4:-1] == '<p>':
            content_front_no_option = content_front_no_option[:-4]
    if content_front_no_option != '':
        content_front_no_option = '<p>' + content_front_no_option + '</p>'
        flag = True
    else:
        content_front_no_option = '<p>' + temp_content + '</p>'
        flag = True
    return flag, option_list, content_front_no_option


def string_2_array(pictures):
    if pictures != '' and 'static' in pictures:
        if '-' not in pictures:
            return [pictures]
        else:
            images = pictures.split('-')
            return images
    else:
        return []


def calc_scale_for_images(pictures_url):
    picture_scale = ''
    for item in pictures_url:
        image = Image.open(item)
        width = image.width
        height = image.height
        scale = str(width) + '@' + str(height)
        picture_scale += scale + '-'
    # 去掉最后一个‘-’
    picture_scale = picture_scale[:-1]
    return picture_scale


# 把pictures字符串压缩图片处理成images数组类型
def pictures2images(pictures=''):
    if pictures == "":
        images = []
    elif "-" in pictures:
        images_temp = pictures.split("-")
        images = [settings.SERVER_IP + image for image in images_temp]
    else:
        images = [settings.SERVER_IP + pictures]
    return images


# pictures_scale字符串类型转换成images_scale数组类型
def pictures_scale2images_scale(pictures_scale):
    result = []
    if pictures_scale == "":
        result = []
    # 两张图片以上，每一张都需要用@符号分离
    elif "-" in pictures_scale:
        images_scale_list = pictures_scale.split("-")
        for item in images_scale_list:
            width, height = item.split('@')
            result.append({'width': width + 'px', 'height': height + 'px'})
    # 没有-符号，则说明只有一张图片，直接用@符号分离即可
    else:
        width, height = pictures_scale.split('@')
        result.append({'width': width + 'px', 'height': height + 'px'})
    return result


def remove_br_head_tail(s):
    return re.sub(r'^(<br>)+|(<br>)+$', '', s)


class QuestionSerializer(serializers.ModelSerializer):
    owner_info = serializers.SerializerMethodField(read_only=True)
    knowledgepoint = serializers.SerializerMethodField(read_only=True)
    type_cn = serializers.SerializerMethodField(read_only=True)
    open_level_cn = serializers.SerializerMethodField(read_only=True)
    favorite_count = serializers.SerializerMethodField(read_only=True)
    publish_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    application_info = serializers.SerializerMethodField(read_only=True)
    content_front_no_option = serializers.SerializerMethodField(read_only=True)
    option_list = serializers.SerializerMethodField(read_only=True)
    video_src = serializers.SerializerMethodField(read_only=True)
    qr_code_url = serializers.SerializerMethodField(read_only=True)
    tag = serializers.SerializerMethodField(read_only=True)

    def get_tag(self, obj):
        return obj.tag.all().values('id', 'name')

    def get_qr_code_url(self, obj):
        video = Video.objects.filter(question__id=obj.id)
        src = ''
        if video:
            video = video.first()
            src = video.url
            if settings.CURRENT_DOMAIN not in src:
                src = self.replace_urls(content=src, current_domain=settings.CURRENT_DOMAIN)
        return src

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'content' in data:
            if settings.CURRENT_DOMAIN not in data['content']:
                data['content'] = self.replace_urls(content=data['content'], current_domain=settings.CURRENT_DOMAIN)
        if 'answer' in data:
            if settings.CURRENT_DOMAIN not in data['answer']:
                data['answer'] = self.replace_urls(content=data['answer'], current_domain=settings.CURRENT_DOMAIN)
        if 'explain' in data:
            if settings.CURRENT_DOMAIN not in data['explain']:
                data['explain'] = self.replace_urls(content=data['explain'], current_domain=settings.CURRENT_DOMAIN)
        return data

    def replace_urls(self, content, current_domain):
        """替换内容中的域名"""
        # 正则表达式模式：匹配以http开头，任意非空格字符，直到/static前的部分
        pattern = r'(http[s]?://[^/]+)(/static)'

        def replace_match(match):
            domain = match.group(1)
            static_part = match.group(2)
            if domain != current_domain:
                return current_domain + static_part
            return match.group(0)
        return re.sub(pattern, replace_match, content)

    def get_video_src(self, obj):
        video = Video.objects.filter(question__id=obj.id)
        src = ''
        if video:
            video = video.first()
            src = settings.SERVER_IP_VIDEO + '/' + video.url
        return src

    def get_content_front_no_option(self, obj):
        content2 = obj.content
        if settings.CURRENT_DOMAIN not in content2:
            self.replace_urls(content2, settings.CURRENT_DOMAIN)
        if obj.type not in [1, 3, 4]:
            return content2
        flag, option_list, content_no_option = get_option(content2)
        if flag:
            return content_no_option
        else:
            return content2

    def get_option_list(self, obj):
        if obj.type not in [1, 3, 4]:
            return []
        content = obj.content
        flag, option_list, content_no_option = get_option(content)
        if (obj.type == 1 or obj.type == 3) and len(option_list) == 0:
            option_list = ['A.如图A所示', 'B.如图B所示', 'C.如图C所示', 'D.如图D所示']
        elif obj.type == 4 and len(option_list) == 0:
            option_list = ['A.正确', 'B.错误']
        return option_list

    def get_owner_info(self, obj):
        owner_obj = obj.owner
        return {'id': owner_obj.id, 'username': owner_obj.username, 'nickname': owner_obj.nickname}

    def get_knowledgepoint(self, obj):
        return obj.knowledgepoint_set.all().values('id', 'name')

    def get_favorite_count(self, obj):
        favorite_queryset = obj.favorite.all()
        return favorite_queryset.count()

    def get_type_cn(self, obj):
        return obj.get_type_display()

    def get_open_level_cn(self, obj):
        return obj.get_open_level_display()

    def get_application_info(self, obj):
        application = obj.QuestionOnlineApplication.all()
        result = {}
        if application:
            application = application[0]
            result = {'id': application.id, "status": application.status,
                      "status_cn": APPLICATION_STATUS_CHOICE[application.status][1]
                      }
        return result

    class Meta:
        list_serializer_class = QuestionListSerializer
        model = Questions
        fields = ["id", 'content', 'answer', 'explain', 'reference', 'type', 'type_cn', 'difficulty_level',
                  'publish_time', 'open_level', 'open_level_cn', 'top', 'knowledgepoint',
                  'order', 'owner_info', 'owner', 'favorite_count', 'online', 'application_info', 'bank_point',
                  'option_list', 'content_front_no_option', 'expiration', 'video', 'video_src', 'qr_code_url', 'tag',
                  ]
        extra_kwargs = {'owner': {"write_only": True}, 'knowledgepoint': {"read_only": True},
                        }

    def create(self, validated_data):
        # question_dict = validated_data
        question_obj = Questions.objects.create(**validated_data)
        return question_obj


class QuestionPrivateSerializer(serializers.ModelSerializer):
    node = serializers.SerializerMethodField(read_only=True)
    owner_info = serializers.SerializerMethodField(read_only=True)
    tag = serializers.SerializerMethodField(read_only=True)
    type_cn = serializers.SerializerMethodField(read_only=True)
    open_level_cn = serializers.SerializerMethodField(read_only=True)
    publish_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    application_info = serializers.SerializerMethodField(read_only=True)

    def get_node(self, obj):
        return obj.node_set.all().values('id', 'name')

    def get_owner_info(self, obj):
        owner_obj = obj.owner
        return {'id': owner_obj.id, 'username': owner_obj.username, 'nickname': owner_obj.nickname}

    def get_tag(self, obj):
        return obj.tag.all().values('id', 'name')

    def get_type_cn(self, obj):
        return obj.get_type_display()

    def get_open_level_cn(self, obj):
        return obj.get_open_level_display()

    def get_application_info(self, obj):
        application = obj.QuestionPrivateOnlineApplication.all()
        result = {}
        if application:
            application = application[0]
            result = {'id': application.id, "status": application.status,
                      "status_cn": APPLICATION_STATUS_CHOICE[application.status][1]
                      }
        return result

    class Meta:
        list_serializer_class = QuestionListSerializer
        model = Question
        fields = ["id", 'content', 'answer', 'explain', 'reference', 'type', 'type_cn', 'difficulty_level',
                  'publish_time', 'open_level', 'open_level_cn', 'top', 'tag', 'node',
                  'order', 'owner_info', 'owner', 'online', 'application_info',
                  ]
        extra_kwargs = {'owner': {"write_only": True}, 'tag': {"read_only": True}, 'node': {"read_only": True},
                        }

    # def create(self, validated_data):
    #     question_obj = Questions.objects.create(**validated_data)
    #     return question_obj


class ExaminationPaperListSerializer(ListSerializer):
    def update(self, instance, validated_data):
        for index, obj in enumerate(instance):
            self.child.update(obj, validated_data[index])
        return instance


class ExaminationPaperModelSerializer(serializers.ModelSerializer):
    owner_id = serializers.CharField(read_only=True, source="owner.id")
    add_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    expiration = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    questions = QuestionSerializer(many=True)
    application_info = serializers.SerializerMethodField(read_only=True)

    def get_application_info(self, obj):
        result = {}
        application = obj.GeneralPaperApplication.all()
        # print("非联考试卷申请：", application)
        if not application:
            application = obj.JointPaperApplication.all()
        if application:
            application = application[0]
            result = {'id': application.id, "status": application.status,
                      "status_cn": APPLICATION_STATUS_CHOICE[application.status][1]
                      }
        return result

    class Meta:
        list_serializer_class = ExaminationPaperListSerializer
        model = ExaminationPaper
        fields = "__all__"


# 从客户端提交JSON格式的题目列表过来和试卷基本信息，多对多的形式持久化到数据库
class ExaminationPaperModelDeSerializer(serializers.ModelSerializer):
    class Meta:
        model = ExaminationPaper
        fields = ('title', 'publish_time',)

    def create(self, validated_data):
        owner = self.context['request'].user
        paper_dict = validated_data
        paper_information_dict = paper_dict["paperInformation"]
        paper_information_dict["owner"] = owner
        paper_obj = ExaminationPaper.objects.create(**paper_information_dict)
        question_list = paper_dict["questionList"]
        for question_dict in question_list:
            question_dict["owner"] = owner
        paper_obj.questions.add(*question_list)
        return paper_obj


class QuestionUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Questions
        fields = ['id', 'content', 'answer', 'explain', 'reference', 'type', 'difficulty_level',
                  'open_level', 'top', 'knowledgepoint', 'pictures', 'pictures_explain', 'bank_point']

    def update(self, instance, validated_data):
        knowledgepoint_pk = validated_data.get('knowledgepoint', instance.knowledgepoint_pk)
        instance.knowledgepoint = KnowledgePoint.objects.get(pk=knowledgepoint_pk)
        owner_pk = validated_data.get('owner', instance.owner_pk)
        instance.owner = User.objects.get(pk=owner_pk)
        instance.save()
        return instance


class QuestionAllSerializer(serializers.ModelSerializer):
    class Meta:
        model = Questions
        fields = "__all__"


class KnowledgePointContainQuestionSerializer(serializers.ModelSerializer):
    questions = QuestionAllSerializer(many=True)

    class Meta:
        model = KnowledgePoint
        fields = "__all__"
        depth = 1


class SectionContainQuestionSerializer(serializers.ModelSerializer):
    knowledgepoints = KnowledgePointContainQuestionSerializer(many=True)

    class Meta:
        model = Section
        fields = "__all__"
        depth = 1


class SectionSerializer(serializers.ModelSerializer):
    knowledgepoints = KnowledgePointSerializer(many=True)

    class Meta:
        model = Section
        fields = "__all__"


class ChapterSerializer(serializers.ModelSerializer):
    sections = SectionSerializer(many=True)

    class Meta:
        model = Chapter
        fields = "__all__"


class ChapterContainQuestionSerializer(serializers.ModelSerializer):
    sections = SectionContainQuestionSerializer(many=True)

    class Meta:
        model = Chapter
        fields = "__all__"


class CourseSerializer(serializers.ModelSerializer):
    chapters = ChapterSerializer(many=True)

    class Meta:
        model = Course
        fields = "__all__"


class CourseContainQuestionSerializer(serializers.ModelSerializer):
    chapters = ChapterContainQuestionSerializer(many=True)

    class Meta:
        model = Course
        fields = "__all__"


class SubjectSerializer(serializers.ModelSerializer):
    courses = CourseSerializer(many=True)

    class Meta:
        model = Subject
        fields = "__all__"


class SubjectDeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Subject
        fields = "__all__"


class SubjectContainQuestionSerializer(serializers.ModelSerializer):
    courses = CourseContainQuestionSerializer(many=True)

    class Meta:
        model = Subject
        fields = "__all__"


class Docx2QuestionModelSerializer(serializers.ModelSerializer):
    """
    上传docx文件，保存到数据表中，并读取里面的题目，保存到question数据表中
    """

    class Meta:
        model = ExaminationPaper
        fields = "__all__"


# paper公共属性虚类
class PaperApplicationPublicAttribute(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    status_info = serializers.SerializerMethodField(read_only=True)
    paper_info = serializers.SerializerMethodField(read_only=True)

    def get_paper_info(self, obj):
        paper_obj = obj.paper
        return {'id': paper_obj.id, 'open_level': paper_obj.open_level, 'online': paper_obj.online,
                'grade': paper_obj.get_grade_display(), 'title': paper_obj.title
                }

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'phone': user_obj.phone}

    def get_status_info(self, obj):
        return {'id': obj.status, 'name': obj.get_status_display()}

    class Meta:
        abstract = True


class GeneralPaperApplicationModelSerializer(PaperApplicationPublicAttribute):
    class Meta:
        model = GeneralPaperApplication
        fields = ('id', 'user_info', 'user', 'paper_info', 'status_info', 'status', 'paper', 'add_date')
        extra_kwargs = {'user': {"write_only": True}, 'status': {"write_only": True}, 'paper': {"write_only": True},
                        'add_date': {"read_only": True}, 'status_info': {"read_only": True},
                        'paper_info': {"read_only": True}}


class JointPaperApplicationModelSerializer(PaperApplicationPublicAttribute):
    class Meta:
        model = JointPaperApplication
        fields = ('id', 'user_info', 'user', 'paper_info', 'status_info', 'status', 'paper', 'add_date')
        extra_kwargs = {'user': {"write_only": True}, 'status': {"write_only": True}, 'paper': {"write_only": True},
                        'add_date': {"read_only": True}, 'status_info': {"read_only": True},
                        'paper_info': {"read_only": True}
                        }


online_cn_dic = {False: "下线", True: '上线'}


class GuidePaperApplicationModelSerializer(PaperApplicationPublicAttribute):

    def get_paper_info(self, obj):
        paper_obj = obj.paper
        return {'id': paper_obj.id, 'type_cn': paper_obj.get_type_display(),
                'open_level_cn': paper_obj.get_open_level_display(), 'online_cn': online_cn_dic[paper_obj.online],
                'remark': paper_obj.remark, 'title': paper_obj.title,
                }

    class Meta:
        model = GuidePaperApplication
        fields = ('id', 'user_info', 'user', 'paper_info', 'status_info', 'status', 'paper', 'add_date', 'detail',
                  )
        extra_kwargs = {'user': {"write_only": True}, 'status': {"write_only": True}, 'paper': {"write_only": True},
                        'add_date': {"read_only": True}, 'status_info': {"read_only": True},
                        'paper_info': {"read_only": True}
                        }


class QuestionOnlineApplicationModelSerializer(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    status_info = serializers.SerializerMethodField(read_only=True)
    question_info = serializers.SerializerMethodField(read_only=True)

    def get_question_info(self, obj):
        obj = obj.question
        return QuestionSerializer(obj).data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'phone': user_obj.phone}

    def get_status_info(self, obj):
        return {'id': obj.status, 'name': obj.get_status_display()}

    class Meta:
        model = QuestionOnlineApplication
        fields = ('id', 'user_info', 'user', 'question', 'status_info', 'status', 'add_date', 'question_info',
                  )
        extra_kwargs = {'user': {"write_only": True}, 'question': {"write_only": True}, 'status': {"write_only": True},
                        'add_date': {"read_only": True}, 'status_info': {"read_only": True},
                        }


class QuestionPrivateOnlineApplicationModelSerializer(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    status_info = serializers.SerializerMethodField(read_only=True)
    question_info = serializers.SerializerMethodField(read_only=True)

    def get_question_info(self, obj):
        obj = obj.question
        return QuestionPrivateSerializer(obj).data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'phone': user_obj.phone}

    def get_status_info(self, obj):
        return {'id': obj.status, 'name': obj.get_status_display()}

    class Meta:
        model = QuestionPrivateOnlineApplication
        fields = ('id', 'user_info', 'user', 'question', 'status_info', 'status', 'add_date', 'question_info',
                  )
        extra_kwargs = {'user': {"write_only": True}, 'question': {"write_only": True}, 'status': {"write_only": True},
                        'add_date': {"read_only": True}, 'status_info': {"read_only": True},
                        }


class GuidePaperSerializer(serializers.ModelSerializer):
    owner_info = serializers.SerializerMethodField(read_only=True)
    knowledgepoint_cn = serializers.SerializerMethodField(read_only=True)
    type_cn = serializers.SerializerMethodField(read_only=True)
    open_level_cn = serializers.SerializerMethodField(read_only=True)
    online_cn = serializers.SerializerMethodField(read_only=True)
    application_info = serializers.SerializerMethodField(read_only=True)
    add_date = serializers.SerializerMethodField(read_only=True)

    def get_add_date(self, obj):
        return obj.add_time.date()

    def get_application_info(self, obj):
        result = {}
        application = obj.GuidePaperApplication.all()
        if application:
            application = application[0]
            result = {'id': application.id, "status": application.status, 'detail': application.detail,
                      "status_cn": APPLICATION_STATUS_CHOICE[application.status][1]
                      }
        return result

    def get_owner_info(self, obj):
        user_obj = obj.owner
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'nickname': user_obj.nickname,
                'phone': user_obj.phone}

    def get_knowledgepoint_cn(self, obj):
        return obj.knowledgepoint.name

    def get_type_cn(self, obj):
        return obj.get_type_display()

    def get_open_level_cn(self, obj):
        return obj.get_open_level_display()

    def get_online_cn(self, obj):
        if obj.online:
            return "上线"
        else:
            return "下线"

    class Meta:
        model = GuidePaper
        fields = ('id', 'owner_info', 'owner', 'knowledgepoint_cn', 'knowledgepoint', 'type_cn', 'type', 'open_level',
                  'open_level_cn', 'online', 'online_cn', 'add_time', 'add_date', 'title', 'remark', 'file',
                  'application_info', 'bank_point', 'download_total')
        extra_kwargs = {'owner': {"write_only": True}, 'owner_info': {"read_only": True},
                        'knowledgepoint_cn': {"read_only": True},
                        'open_level_cn': {"read_only": True}, 'online_cn': {"read_only": True},
                        'application_info': {"read_only": True}, 'add_date': {"read_only": True},
                        }


class KnowledgePointContainGuidePaperSerializer(serializers.ModelSerializer):
    guide_papers = GuidePaperSerializer(many=True)
    owner = UserSimpleModelSerializer()

    class Meta:
        model = KnowledgePoint
        fields = "__all__"
        depth = 1


class SectionContainGuidePaperSerializer(serializers.ModelSerializer):
    knowledgepoints = KnowledgePointContainGuidePaperSerializer(many=True)

    class Meta:
        model = Section
        fields = "__all__"
        depth = 1


class ChapterContainGuidePaperSerializer(serializers.ModelSerializer):
    sections = SectionContainGuidePaperSerializer(many=True)

    class Meta:
        model = Chapter
        fields = "__all__"


class CourseContainGuidePaperSerializer(serializers.ModelSerializer):
    chapters = ChapterContainGuidePaperSerializer(many=True)

    class Meta:
        model = Course
        fields = "__all__"


class QuestionFeedbackModelSerializer(serializers.ModelSerializer):
    """
       序列化，后端序列化给前端，其中题目只返回其内容和id
    """
    owner = UserSimpleModelSerializer()
    question = QuestionSerializer()
    add_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)

    class Meta:
        model = QuestionFeedback
        fields = "__all__"


class QuestionFeedbackModelDeSerializer(serializers.ModelSerializer):
    """
       反序列化，前端序列化给后端，owner不做要求，并通过create创建反馈者
    """

    class Meta:
        model = QuestionFeedback
        fields = ['content', 'question']

    # 添加拥有者
    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        feedback_object = QuestionFeedback.objects.create(**validated_data)
        return feedback_object


class FeedbackModelSerializer(serializers.ModelSerializer):
    """
       序列化，后端序列化给前端，其中题目只返回其内容和id
    """
    owner = UserSimpleModelSerializer()
    add_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)

    class Meta:
        model = Feedback
        fields = "__all__"


class FeedbackModelDeSerializer(serializers.ModelSerializer):
    """
       反序列化，前端序列化给后端，owner不做要求，并通过create创建反馈者
    """

    class Meta:
        model = Feedback
        fields = ['content']

    # 添加拥有者, 并将列表串联成字符串，存储在pictures字段中
    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        feedback_object = Feedback.objects.create(**validated_data)
        return feedback_object


class GuidePaperFeedbackModelSerializer(serializers.ModelSerializer):
    """
       序列化，后端序列化给前端，其中题目只返回其内容和id
    """
    owner = UserSimpleModelSerializer()
    paper = GuidePaperSerializer()
    add_time = serializers.DateTimeField(format=date_format, required=False, read_only=True)

    class Meta:
        model = GuidePaperFeedback
        fields = "__all__"


class GuidePaperFeedbackModelDeSerializer(serializers.ModelSerializer):
    """
       反序列化，前端序列化给后端，owner不做要求，并通过create创建反馈者
    """

    class Meta:
        model = GuidePaperFeedback
        fields = ['content', 'paper']

    # 添加拥有者
    def create(self, validated_data):
        owner = self.context['request'].user
        validated_data['owner'] = owner
        feedback_object = GuidePaperFeedback.objects.create(**validated_data)
        return feedback_object


class DownloadGuidePaperLogModelSerializer(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    guide_paper_info = serializers.SerializerMethodField(read_only=True)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'add_time' in data:
            data['add_date'] = data['add_time'][:10]
        data['status_cn'] = TRANSACTION_STATUS_CHOICE[data['status']-1][1]
        return data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'nickname': user_obj.nickname,
                'phone': user_obj.phone, 'bank_pint': user_obj.bank_point, 'inviter_number': user_obj.inviter_number}

    def get_guide_paper_info(self, obj):
        paper_obj = obj.guide_paper
        return {'title': paper_obj.title, 'owner': paper_obj.owner.nickname}

    class Meta:
        model = DownloadGuidePaperLog
        fields = "__all__"
        extra_kwargs = {'user_info': {"read_only": True}, 'guide_paper_info': {"read_only": True}}


class DownloadQuestionLogModelSerializer(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    question_info = serializers.SerializerMethodField(read_only=True)
    result_info = serializers.SerializerMethodField(read_only=True)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'add_time' in data:
            data['add_date'] = data['add_time'][:10]
        data['status_cn'] = TRANSACTION_STATUS_CHOICE[data['status']-1][1]
        return data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'nickname': user_obj.nickname,
                'phone': user_obj.phone, 'bank_pint': user_obj.bank_point, 'inviter_number': user_obj.inviter_number}

    def get_result_info(self, obj):
        result_dic = {'0': '正确', '1': '错误'}
        result = obj.result
        data_list = []
        for item in result:
            question_id, result_item = item.split(',')
            question = Questions.objects.get(pk=question_id)
            question_front = QuestionSerializer(question).data
            result_front = result_dic[result_item]
            data_list.append({'question': question_front, 'result': result_front})
        return data_list

    def get_question_info(self, obj):
        question_obj = obj.question
        return {'title': question_obj.title, 'owner': question_obj.owner.nickname}

    class Meta:
        model = DownloadQuestionLog
        fields = "__all__"
        extra_kwargs = {'user_info': {"read_only": True}, 'guide_paper_info': {"read_only": True}}


class DownloadExaminationPaperLogModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = DownloadExaminationPaperLog
        fields = "__all__"


class ChallengePaperOfUserModelSerializer(serializers.ModelSerializer):
    user_info = serializers.SerializerMethodField(read_only=True)
    paper_info = serializers.SerializerMethodField(read_only=True)

    def get_paper_info(self, obj):
        paper_obj = obj.paper
        return {'id': paper_obj.id, 'open_level': paper_obj.open_level, 'online': paper_obj.online,
                'grade': paper_obj.get_grade_display(), 'title': paper_obj.title
                }

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'add_time' in data:
            data['add_date'] = data['add_time'][:10]
        print(data['accuracy'])
        data['accuracy_cn'] = str(float(data['accuracy'])*100)+"%"
        print("正确率", data['accuracy_cn'])
        return data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'nickname': user_obj.nickname,
                'phone': user_obj.phone, 'bank_pint': user_obj.bank_point, 'inviter_number': user_obj.inviter_number}

    class Meta:
        model = ChallengePaperOfUser
        fields = "__all__"
        extra_kwargs = {'user_info': {"read_only": True}, 'paper_info': {"read_only": True},
                        'result_info': {"read_only": True}}


class WrongQuestionModelSerializer(serializers.ModelSerializer):
    question_info = serializers.SerializerMethodField(read_only=True)
    user_info = serializers.SerializerMethodField(read_only=True)

    def get_question_info(self, obj):
        obj = obj.question
        return QuestionSerializer(obj).data

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'add_time' in data:
            data['add_date'] = data['add_time'][:10]
        return data

    def get_user_info(self, obj):
        user_obj = obj.user
        return {'id': user_obj.id, 'real_name': user_obj.real_name, 'nickname': user_obj.nickname,
                'phone': user_obj.phone, 'bank_pint': user_obj.bank_point, 'inviter_number': user_obj.inviter_number}

    class Meta:
        model = WrongQuestion
        fields = "__all__"
        extra_kwargs = {'user_info': {"read_only": True}, 'question_info': {"read_only": True}}


class SwiperImageModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SwiperImage
        fields = '__all__'


class BulletinModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Bulletin
        fields = '__all__'


class CategoryModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'


class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'


class PermitExplainPaperOfUserModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = PermitExplainPaperOfUser
        fields = "__all__"


class UserDoQuestionLogModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDoQuestionLog
        fields = "__all__"


def replace_urls(content, current_domain):
    """替换内容中的域名"""
    # 正则表达式模式：匹配以http开头，任意非空格字符，直到/static前的部分
    pattern = r'(http[s]?://[^/]+)(/static)'

    def replace_match(match):
        domain = match.group(1)
        static_part = match.group(2)
        if domain != current_domain:
            return current_domain + static_part
        return match.group(0)
    return re.sub(pattern, replace_match, content)


class VideoModelSerializer(serializers.ModelSerializer):
    qr_code = serializers.ImageField(required=False)

    class Meta:
        model = Video
        fields = ('id', 'add_time', 'price', 'url', 'qr_code', 'question', 'owner')

    def to_representation(self, instance):
        data = super().to_representation(instance)
        if 'url' in data and data['url'] != '':
            if settings.CURRENT_DOMAIN not in data['url']:
                data['url'] = replace_urls(content=data['url'], current_domain=settings.CURRENT_DOMAIN)
            url = unquote(data['url'])
            paper_index = url.find('.top') + 5
            data['url_utf8'] = url[paper_index:-11]
        else:
            data['url_utf8'] = unquote(data['url'])
        if 'add_time' in data and data['add_time'] != '':
            data['add_date'] = data['add_time'][:10]
        else:
            data['add_date'] = data['add_time']
        return data

    def create(self, validated_data):
        print('serializer create!')
        print('validated_data:', validated_data)
        image_path = validated_data.pop('qr_code', None)
        instance = super().create(validated_data)
        if image_path:
            print('now save qr_code field!')
            # 处理上传的图片，保存到模型实例对应的image字段
            image_name = image_path.split('/')[-1]
            instance.qr_code.save(image_name, open(image_path, 'rb'), save=True)
        return instance

    def update(self, instance, validated_data):
        print('serializer update!')
        print('validated_data:', validated_data)
        image_path = validated_data.pop('qr_code', None)
        instance = super().update(instance, validated_data)
        if image_path:
            # 处理上传的图片，保存到模型实例对应的image字段
            image_name = image_path.split('/')[-1]
            instance.qr_code.save(image_name, open(image_path, 'rb'), save=True)
        return instance


class PermitVideoOfQuestionModelSerializer(serializers.ModelSerializer):
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)

    class Meta:
        model = PermitVideoOfQuestion
        fields = "__all__"


class UserPlayVideoLogModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserPlayVideoLog
        fields = "__all__"


# 私有题库的标签
class Tag2QuestionModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag2Question
        fields = "__all__"


# 公有题库的标签
class TagQuestionModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = TagQuestion
        fields = "__all__"


class SeatworkModelSerializer(serializers.ModelSerializer):
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)
    owner_name = serializers.CharField(source='owner.username', read_only=True)
    question_info = serializers.SerializerMethodField(read_only=True, required=False)

    def get_question_info(self, obj):
        seatwork_obj = Seatwork.objects.get(id=obj.id)
        question = seatwork_obj.question.all()
        result = QuestionSerializer(question, many=True).data
        return result

    def create(self, validated_data):
        work_obj = super().create(validated_data)
        question_list = self.initial_data["question_list"]
        work_obj.question.add(*question_list)
        return work_obj

    class Meta:
        model = Seatwork
        fields = "__all__"


class QuestionOfWorkModelSerializer(serializers.ModelSerializer):
    add_date = serializers.DateTimeField(format=date_format, required=False, read_only=True)

    class Meta:
        model = QuestionOfWork
        fields = "__all__"


# 用于反序列化
class SetWorkSimpleModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = SetWork
        fields = "__all__"


class SetWorkForStudentModelSerializer(serializers.ModelSerializer):
    add_date = serializers.SerializerMethodField(read_only=True, required=False)
    seatwork_info = serializers.SerializerMethodField(read_only=True, required=False)
    teacher_info = serializers.SerializerMethodField(read_only=True, required=False)
    class_list = serializers.SerializerMethodField(read_only=True, required=False)
    open_cn = serializers.SerializerMethodField(read_only=True)
    permit_cn = serializers.SerializerMethodField(read_only=True)

    def get_add_date(self, obj):
        date = str(obj.add_time)
        return date[:10]

    def get_teacher_info(self, obj):
        teacher_obj = obj.teacher
        result = UserSimpleModelSerializer(teacher_obj).data
        return result

    def get_seatwork_info(self, obj):
        seatwork_obj = obj.seatwork
        result = SeatworkModelSerializer(seatwork_obj).data
        return result

    def get_class_list(self, obj):
        setwork_obj = SetWork.objects.get(id=obj.id)
        # result = setwork_obj.class_grade.all().values('id', 'name', 'graduated')
        class_grade = setwork_obj.class_grade.all()
        result = ClassGradeModelSerializer(class_grade, many=True).data
        return result

    def get_open_cn(self, obj):
        if obj.open_answer:
            return '开'
        else:
            return '关'

    def get_permit_cn(self, obj):
        if obj.permit_write:
            return '允许答题'
        else:
            return '关闭答题'

    class Meta:
        model = SetWork
        fields = "__all__"


class SetWorkModelSerializer(serializers.ModelSerializer):
    add_date = serializers.SerializerMethodField(read_only=True, required=False)
    seatwork_info = serializers.SerializerMethodField(read_only=True, required=False)
    teacher_info = serializers.SerializerMethodField(read_only=True, required=False)
    class_info = serializers.SerializerMethodField(read_only=True, required=False)
    class_list = serializers.SerializerMethodField(read_only=True, required=False)
    # class_grade = ClassGradeModelSerializer(read_only=True, many=True)
    open_cn = serializers.SerializerMethodField(read_only=True)
    permit_cn = serializers.SerializerMethodField(read_only=True)

    def get_add_date(self, obj):
        date = str(obj.add_time)
        return date[:10]

    def get_teacher_info(self, obj):
        result = {'id': obj.teacher.id, 'username': obj.teacher.username}
        # result = User.objects.get(id=obj.teacher.id).values('id', 'username')
        return result

    def get_seatwork_info(self, obj):
        seatwork_obj = obj.seatwork
        result = SeatworkModelSerializer(seatwork_obj).data
        return result

    def get_class_list(self, obj):
        setwork_obj = SetWork.objects.get(id=obj.id)
        class_grade = setwork_obj.class_grade.all()
        result = ClassGradeModelSerializer(class_grade, many=True).data
        return result

    def get_class_info(self, obj):
        setwork_obj = SetWork.objects.get(id=obj.id)
        # result = setwork_obj.class_grade.all().values('id', 'name', 'graduated')
        class_grade = setwork_obj.class_grade.all()
        result = ClassGradeModelSerializer(class_grade, many=True).data
        return result

    def get_open_cn(self, obj):
        if obj.open_answer:
            return '开'
        else:
            return '关'

    def get_permit_cn(self, obj):
        if obj.permit_write:
            return '允许答题'
        else:
            return '关闭答题'

    class Meta:
        model = SetWork
        fields = "__all__"


class WorkRecordModelSerializer(serializers.ModelSerializer):
    add_date = serializers.SerializerMethodField(required=False, read_only=True)
    setwork_info = serializers.SerializerMethodField(required=False, read_only=True)
    user_info = serializers.SerializerMethodField(required=False, read_only=True)
    WorkRecordItem = serializers.SerializerMethodField(required=False, read_only=True)

    def get_add_date(self, obj):
        date = str(obj.add_time)
        return date[:10]

    def get_WorkRecordItem(self, obj):
        record_item_list = obj.WorkRecordItem
        result = WorkRecordItemModelSerializer(record_item_list, many=True).data
        return result

    def get_user_info(self, obj):
        user = obj.user
        # result = UserSimpleModelSerializer(user).data
        result = {'id': user.id, 'username': user.username}
        return result

    def get_setwork_info(self, obj):
        object = obj.setwork
        result = SetWorkModelSerializer(object).data
        return result

    class Meta:
        model = WorkRecord
        fields = "__all__"


class WorkRecordItemModelSerializer(serializers.ModelSerializer):
    question_info = serializers.SerializerMethodField(required=False, read_only=True)

    def get_question_info(self, obj):
        question_obj = Questions.objects.get(id=obj.question.id)
        result = {'content': question_obj.content, 'answer': question_obj.answer, 'explain': question_obj.explain }
        return result

    class Meta:
        model = WorkRecordItem
        fields = "__all__"

